
#include "encrythionimpl.h"
#include "openssl/md5.h"  
#include "openssl/sha.h"  
#include "openssl/des.h"  
#include "openssl/rsa.h"  
#include "openssl/pem.h"  
 
// ---- md5摘要哈希 ---- //  
void EncrythionImpl::md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
	// 调用md5哈希  
	unsigned char mdStr[33] = {0};
	MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
 
	// 哈希后的字符串  
	encodedStr = std::string((const char *)mdStr);
	// 哈希后的十六进制串 32字节  
	char buf[65] = {0};
	char tmp[3] = {0};
	for (int i = 0; i < 32; i++)
	{
		sprintf(tmp, "%02x", mdStr[i]);
		strcat(buf, tmp);
	}
	buf[32] = '\0'; // 后面都是0，从32字节截断  
	encodedHexStr = std::string(buf);
}
 
// ---- sha256摘要哈希 ---- //  
void EncrythionImpl::sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
	// 调用sha256哈希  
	unsigned char mdStr[33] = {0};
	SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);
 
	// 哈希后的字符串  
	encodedStr = std::string((const char *)mdStr);
	// 哈希后的十六进制串 32字节  
	char buf[65] = {0};
	char tmp[3] = {0};
	for (int i = 0; i < 32; i++)
	{
		sprintf(tmp, "%02x", mdStr[i]);
		strcat(buf, tmp);
	}
	buf[32] = '\0'; // 后面都是0，从32字节截断  
	encodedHexStr = std::string(buf);
}
 
// ---- des对称加解密 ---- //  
// 加密 ecb模式  
std::string EncrythionImpl::des_encrypt(const std::string &clearText, const std::string &key)
{
	std::string cipherText; // 密文  
 
	DES_cblock keyEncrypt;
	memset(keyEncrypt, 0, 8);
 
	// 构造补齐后的密钥  
	if (key.length() <= 8)
		memcpy(keyEncrypt, key.c_str(), key.length());
	else
		memcpy(keyEncrypt, key.c_str(), 8);
 
	// 密钥置换  
	DES_key_schedule keySchedule;
	DES_set_key_unchecked(&keyEncrypt, &keySchedule);
 
	// 循环加密，每8字节一次  
	const_DES_cblock inputText;
	DES_cblock outputText;
	std::vector<unsigned char> vecCiphertext;
	unsigned char tmp[8];
 
	for (int i = 0; i < clearText.length() / 8; i++)
	{
		memcpy(inputText, clearText.c_str() + i * 8, 8);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
		memcpy(tmp, outputText, 8);
 
		for (int j = 0; j < 8; j++)
			vecCiphertext.push_back(tmp[j]);
	}
 
	if (clearText.length() % 8 != 0)
	{
		int tmp1 = clearText.length() / 8 * 8;
		int tmp2 = clearText.length() - tmp1;
		memset(inputText, 0, 8);
		memcpy(inputText, clearText.c_str() + tmp1, tmp2);
		// 加密函数  
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
		memcpy(tmp, outputText, 8);
 
		for (int j = 0; j < 8; j++)
			vecCiphertext.push_back(tmp[j]);
	}
 
	cipherText.clear();
	cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());
 
    QByteArray arry(cipherText.c_str(), cipherText.length());
    return arry.toBase64().toStdString();

    //return cipherText;
}
 
// 解密 ecb模式  
std::string EncrythionImpl::des_decrypt(const std::string &cipherText, const std::string &key)
{
	std::string clearText; // 明文  
 
    QByteArray decryptDataArry = QString::fromStdString(cipherText).toUtf8();
    decryptDataArry = QByteArray::fromBase64(decryptDataArry);
    int nDecryptDataLen = decryptDataArry.length();
    uchar* pDecryptData = (uchar*)decryptDataArry.data();

	DES_cblock keyEncrypt;
	memset(keyEncrypt, 0, 8);
 
	if (key.length() <= 8)
		memcpy(keyEncrypt, key.c_str(), key.length());
	else
		memcpy(keyEncrypt, key.c_str(), 8);
 
	DES_key_schedule keySchedule;
	DES_set_key_unchecked(&keyEncrypt, &keySchedule);
 
	const_DES_cblock inputText;
	DES_cblock outputText;
	std::vector<unsigned char> vecCleartext;
	unsigned char tmp[8];
 
    for (int i = 0; i < nDecryptDataLen / 8; i++)
	{
        memcpy(inputText, pDecryptData + i * 8, 8);
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
		memcpy(tmp, outputText, 8);
 
		for (int j = 0; j < 8; j++)
			vecCleartext.push_back(tmp[j]);
	}
 
    if (nDecryptDataLen % 8 != 0)
	{
        int tmp1 = nDecryptDataLen / 8 * 8;
        int tmp2 = nDecryptDataLen - tmp1;
		memset(inputText, 0, 8);
        memcpy(inputText, pDecryptData + tmp1, tmp2);
		// 解密函数  
		DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
		memcpy(tmp, outputText, 8);
 
		for (int j = 0; j < 8; j++)
			vecCleartext.push_back(tmp[j]);
	}
 
	clearText.clear();
	clearText.assign(vecCleartext.begin(), vecCleartext.end());

	return clearText;
}
 
 
// ---- rsa非对称加解密 ---- //  
#define KEY_LENGTH  2048               // 密钥长度
#define PUB_KEY_FILE "pubkey.pem"    // 公钥路径
#define PRI_KEY_FILE "prikey.pem"    // 私钥路径
 
// 函数方法生成密钥对 
void EncrythionImpl::generateRSAKey(std::string strKey[2])
{
	// 公私密钥对  
	size_t pri_len;
	size_t pub_len;
	char *pri_key = NULL;
	char *pub_key = NULL;
 
	// 生成密钥对  
	RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);
 
	BIO *pri = BIO_new(BIO_s_mem());
	BIO *pub = BIO_new(BIO_s_mem());
 
	PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
	PEM_write_bio_RSAPublicKey(pub, keypair);
 
	// 获取长度  
	pri_len = BIO_pending(pri);
	pub_len = BIO_pending(pub);
 
	// 密钥对读取到字符串  
	pri_key = (char *)malloc(pri_len + 1);
	pub_key = (char *)malloc(pub_len + 1);
 
	BIO_read(pri, pri_key, pri_len);
	BIO_read(pub, pub_key, pub_len);
 
	pri_key[pri_len] = '\0';
	pub_key[pub_len] = '\0';
 
	// 存储密钥对  
	strKey[0] = pub_key;
	strKey[1] = pri_key;
 
	// 存储到磁盘（这种方式存储的是begin rsa public key/ begin rsa private key开头的）
	FILE *pubFile = fopen(PUB_KEY_FILE, "w");
	if (pubFile == NULL)
	{
		assert(false);
		return;
	}
	fputs(pub_key, pubFile);
	fclose(pubFile);
 
	FILE *priFile = fopen(PRI_KEY_FILE, "w");
	if (priFile == NULL)
	{
        assert(false);
		return;
	}
	fputs(pri_key, priFile);
	fclose(priFile);
 
	// 内存释放
	RSA_free(keypair);
	BIO_free_all(pub);
	BIO_free_all(pri);
 
	free(pri_key);
	free(pub_key);
}
 
// 命令行方法生成公私钥对（begin public key/ begin private key）
// 找到openssl命令行工具，运行以下
// openssl genrsa -out prikey.pem 1024 
// openssl rsa - in privkey.pem - pubout - out pubkey.pem
 
// 公钥加密  
std::string EncrythionImpl::rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)
{
	std::string strRet;
	RSA *rsa = NULL;
	BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
	if (keybio == NULL){
        return "";
    }
	// 此处有三种方法
	// 1, 读取内存里生成的密钥对，再从内存生成rsa
	// 2, 读取磁盘里生成的密钥对文本文件，在从内存生成rsa
	// 3，直接从读取文件指针生成rsa
	RSA* pRSAPublicKey = RSA_new();
	rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
    if ( rsa == NULL ){
         BIO_free_all(keybio);
         return "";
    }
	
	int len = RSA_size(rsa);
	char *encryptedText = (char *)malloc(len + 1);
	memset(encryptedText, 0, len + 1);
 
	// 加密函数
	int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);
	if (ret >= 0)
		strRet = std::string(encryptedText, ret);
 
    QString strEncryptData = "";
    if ( ret >= 0 ){
         QByteArray arry(encryptedText, ret);
         strEncryptData = arry.toBase64();
    }

	// 释放内存
	free(encryptedText);
	BIO_free_all(keybio);
	RSA_free(rsa);
 
    return strEncryptData.toStdString();
}
 
// 私钥解密  
std::string EncrythionImpl::rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)
{
    if(priKey.empty() || cipherText.empty())
        return "";

	std::string strRet;
	RSA *rsa = RSA_new();
	BIO *keybio;
	keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
    if (keybio == NULL){
        return "";
    }

	// 此处有三种方法
	// 1, 读取内存里生成的密钥对，再从内存生成rsa
	// 2, 读取磁盘里生成的密钥对文本文件，在从内存生成rsa
	// 3，直接从读取文件指针生成rsa
	rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
    if ( rsa == NULL ){
         BIO_free_all(keybio);
         return "";
    }

	int len = RSA_size(rsa);
	char *decryptedText = (char *)malloc(len + 1);
	memset(decryptedText, 0, len + 1);
 
	// 解密函数
    QByteArray decryptDataArry = QString::fromStdString(cipherText).toUtf8();
    decryptDataArry = QByteArray::fromBase64(decryptDataArry);
    int nDecryptDataLen = decryptDataArry.length();
    uchar* pDecryptData = (uchar*)decryptDataArry.data();
    int ret = RSA_private_decrypt(nDecryptDataLen, pDecryptData, (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
	if (ret >= 0)
		strRet = std::string(decryptedText, ret);
 
	// 释放内存
	free(decryptedText);
	BIO_free_all(keybio);
	RSA_free(rsa);
 
	return strRet;
}
 

//私钥加密
QString EncrythionImpl::rsa_pri_encrypt_base64 (const QString& strClearData, const std::string &priKey)
{
    //私钥  长度为512  （使用自己生成的公秘钥）
    char private_key[] = "-----BEGIN PRIVATE KEY-----\n"\
            "MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAzpXEGSjFGDRdr4Gp\n"\
            "k/impFrqxw0JUs7oUwTheJgqNIfCJfw00PHOKmIDI9UoS+E3Ozs1reMP1r0IuUys\n"\
            "zX5LGwIDAQABAkEAhUCjcdsTbu5wM8H+QT0VOFSQtf5ZsjlWMB6o1SHJr4Fs8UEE\n"\
            "7JHUTGrlUopMrhQDfYxGqDUAXykca99xu8e1QQIhAPPdcze2DeV5X9a8bcd3VEzK\n"\
            "Luy6SMOtomEMUKPlYEa7AiEA2N1puJwKEulYWaHywLwhA8tM08YFsFqh18JsUbP5\n"\
            "NyECIQCtuykXGnLB9XsqfyjyPnfnEO7nJTsrdGrHGr/kU0gIewIgVWqYGntzSFGa\n"\
            "V+t+psUyp8DqaLslQHniJw5QBbpCXaECIQDgDWRfFb7h68XMi2fpkd727YDpl64p\n"\
            "fb2H/qFyq3xBDw==\n"\
            "-----END PRIVATE KEY-----";

    //将字符串键加载到bio对象
    //BIO* pKeyBio = BIO_new_mem_buf(priKey.c_str(), -1);
    BIO* pKeyBio = BIO_new_mem_buf(private_key, -1);
    if (pKeyBio == NULL){
        return "";
    }
    RSA* pRsa = RSA_new();
    pRsa = PEM_read_bio_RSAPrivateKey(pKeyBio, &pRsa, NULL, NULL);
    if ( pRsa == NULL ){
         BIO_free_all(pKeyBio);
         return "";
    }
    int nLen = RSA_size(pRsa);
    char* pEncryptBuf = new char[nLen];
    memset(pEncryptBuf, 0, nLen);
    QByteArray clearDataArry = strClearData.toUtf8();
    int nClearDataLen = clearDataArry.length();
    uchar* pClearData = (uchar*)clearDataArry.data();
    int nSize = RSA_private_encrypt(nClearDataLen,
                                    pClearData,
                                    (uchar*)pEncryptBuf,
                                    pRsa,
                                    RSA_PKCS1_PADDING);

    QString strEncryptData = "";
    if ( nSize >= 0 ){
         QByteArray arry(pEncryptBuf, nSize);
         strEncryptData = arry.toBase64();
    }
    // 释放内存
    delete pEncryptBuf;
    BIO_free_all(pKeyBio);
    RSA_free(pRsa);
    return strEncryptData;
}

//公钥解密
QString EncrythionImpl::rsa_pub_decrypt_base64(const QString& strDecryptData, const std::string &pubKey)
{

    //公钥解密
    char public_key[] = "-----BEGIN PUBLIC KEY-----\n"\
            "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM6VxBkoxRg0Xa+BqZP4pqRa6scNCVLO\n"\
            "6FME4XiYKjSHwiX8NNDxzipiAyPVKEvhNzs7Na3jD9a9CLlMrM1+SxsCAwEAAQ==\n"\
            "-----END PUBLIC KEY-----";

    //将字符串键加载到bio对象
    BIO* pKeyBio = BIO_new_mem_buf(public_key, -1);
    //BIO* pKeyBio = BIO_new_mem_buf(pubKey.c_str(), pubKey.length());
    if (pKeyBio == NULL){
        return "";
    }

    RSA* pRsa = RSA_new();

    pRsa = PEM_read_bio_RSA_PUBKEY(pKeyBio, &pRsa, NULL, NULL);


    if ( pRsa == NULL ){
        BIO_free_all(pKeyBio);
        return "";
    }
    int nLen = RSA_size(pRsa);
    char* pClearBuf = new char[nLen];
    memset(pClearBuf, 0, nLen);
    //解密
    QByteArray decryptDataArry = strDecryptData.toUtf8();
    decryptDataArry = QByteArray::fromBase64(decryptDataArry);
    int nDecryptDataLen = decryptDataArry.length();
    uchar* pDecryptData = (uchar*)decryptDataArry.data();
    int nSize = RSA_public_decrypt(nDecryptDataLen,
                                   pDecryptData,
                                   (uchar*)pClearBuf,
                                   pRsa,
                                   RSA_PKCS1_PADDING);
    QString strClearData = "";
    if ( nSize >= 0 ){
        strClearData = QByteArray(pClearBuf, nSize);
    }

    // 释放内存
    delete pClearBuf;
    BIO_free_all(pKeyBio);
    RSA_free(pRsa);
    return strClearData;
}

//int main(int argc, char **argv)
//{
//	// 原始明文
//	std::string srcText = "this is an DTK example this is a way, this is a way this is way if you miss the train i am on";
 
//	std::string encryptText;
//	std::string encryptHexText;
//	std::string decryptText;
 
//	std::cout << "=== 原始明文 ===" << std::endl;
//	std::cout << srcText << std::endl;
 
//	// md5
//	std::cout << "=== md5哈希 ===" << std::endl;
//	md5(srcText, encryptText, encryptHexText);
//	std::cout << "摘要字符： " << encryptText << std::endl;
//	std::cout << "摘要串： " << encryptHexText << std::endl;
 
//	// sha256
//	std::cout << "=== sha256哈希 ===" << std::endl;
//	sha256(srcText, encryptText, encryptHexText);
//	std::cout << "摘要字符： " << encryptText << std::endl;
//	std::cout << "摘要串： " << encryptHexText << std::endl;
 
//	// des
//	std::cout << "=== des加解密 ===" << std::endl;
//	std::string desKey = "12345";
//	encryptText = des_encrypt(srcText, desKey);
//	std::cout << "加密字符： " << std::endl;
//	std::cout << encryptText << std::endl;
//	decryptText = des_decrypt(encryptText, desKey);
//	std::cout << "解密字符： " << std::endl;
//	std::cout << decryptText << std::endl;
 
//	// rsa
//	std::cout << "=== rsa加解密 ===" << std::endl;
//	std::string key[2];
//	generateRSAKey(key);
//	std::cout << "公钥: " << std::endl;
//	std::cout << key[0] << std::endl;
//	std::cout << "私钥： " << std::endl;
//	std::cout << key[1] << std::endl;
//	encryptText = rsa_pub_encrypt(srcText, key[0]);
//	std::cout << "加密字符： " << std::endl;
//	std::cout << encryptText << std::endl;
//	decryptText = rsa_pri_decrypt(encryptText, key[1]);
//	std::cout << "解密字符： " << std::endl;
//	std::cout << decryptText << std::endl;
 
//	//system("pause");
//        getchar();
//	return 0;
//}
